package com.hm.health.Utils;

import com.goodix.libromablecom.sdk.cardiff.CardiffDeviceController;
import com.goodix.utils.EncryptUtil;
import com.goodix.utils.TimeUtil;
import com.goodix.libromablecom.sdk.cardiff.CardiffConstants;
import com.goodix.comsdk.entity.MeasureResult;
import com.goodix.comsdk.sdk.OnHBDDataListener;
import com.goodix.http.jsonparams.request.UploadCfgInfoParams;
import com.goodix.iot.libbase.utils.ArrayUtil;
import com.goodix.libromablecom.sdk.cardiff.arguments.StartArgumentsKeyEnum;
import com.google.gson.Gson;
import com.hm.health.MyApplication;
import com.hm.health.entity.BleDevicesInfo;
import com.hm.health.entity.arguments.StartArgumentsManager;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * Created by chenshi on 2019/12/27.
 */

public class FileSaveHandler {
    private Map<String, FileLogUtil> mFileSaveUtilMap = new HashMap<>();
    private String mFilePath;
    private volatile boolean mStop;
    private String mFileHeader;
    private String mStartTestTime;
    private List<String> mAddressList = new ArrayList<>();
    private volatile int[] mValues = new int[16];
    private boolean mReceivedValues = false;
    private boolean mEncryptionRawdata = false;
    private String mFunctionName;
    private List<BleDevicesInfo> mBleDeviceInfos;

    private void reset() {
        mFileSaveUtilMap.clear();
        mFilePath = "";
        mStop = false;
        mFileHeader = "";
        mStartTestTime = "";
        mAddressList.clear();
        Arrays.fill(mValues, 0);
        mReceivedValues = false;
        mEncryptionRawdata = false;
        mFunctionName = "";
        if (null != mBleDeviceInfos) {
            mBleDeviceInfos.clear();
        }
    }

    public void start(String rootPath, String startTestTime, List<BleDevicesInfo> devicesInfos) {
        reset();
        mReceivedValues = false;
        mFilePath = rootPath;
        mStop = false;
        mStartTestTime = startTestTime;
        mFileSaveUtilMap.clear();
        mAddressList.clear();
        Arrays.fill(mValues, 0);
        MyApplication.getHBDTestClient().registerHBDDataListener(mOnHBDDataListener);
        mEncryptionRawdata = MyApplication.getHbdOptionIni().isRawDataEncrypted();
        if (devicesInfos.size() > 1) {
            mBleDeviceInfos = devicesInfos.subList(1, devicesInfos.size());
        } else {
            mBleDeviceInfos = new ArrayList<>();
        }

        for (BleDevicesInfo devicesInfo : mBleDeviceInfos) {
            mAddressList.add(devicesInfo.getDeviceAddress());
        }

        mFunctionName = StartArgumentsManager.getInstance().getFunctionName();
    }

    public void stop() {
        mStop = true;
        MyApplication.getHBDTestClient().unRegisterHBDDataListener(mOnHBDDataListener);
        for (Map.Entry<String, FileLogUtil> entry : mFileSaveUtilMap.entrySet()) {
            entry.getValue().finishedSave();
        }
        mFileSaveUtilMap.clear();
    }

    private void saveData(String dataType, int[] datas) {
        if (mStop) {
            return;
        }

        mFileHeader = CardiffDeviceController.getInstance().getFileHeader(dataType).trim();
        if (mFileHeader.isEmpty()) {
            return;
        }

        if (!mFileSaveUtilMap.containsKey(dataType)) {

            // Create file
            String testerInfo = MyApplication.getInstance().getTesterInfo();
            String fileName = String.format(Locale.ENGLISH,
                    "extra-%s-%s-%s.csv", dataType.toLowerCase(), testerInfo, mStartTestTime);
            FileLogUtil fileLogUtil = new FileLogUtil(mFilePath + dataType.toLowerCase(), fileName);
            if (new File(fileLogUtil.getFilePath() + fileName).exists()) {
                FileUtil.deleteFile(fileLogUtil.getFilePath() + fileName);
            }
            fileLogUtil.startSave();

            // Add upload header
            UploadCfgInfoParams uploadCfgInfoParams = MyApplication.getInstance()
                    .getUploadCfgParam(mBleDeviceInfos, TimeUtil.getTime(mStartTestTime));
            String uploadHeader = new Gson().toJson(uploadCfgInfoParams);
            fileLogUtil.saveData(uploadHeader + "\n");

            // Add data column information
            int firstDots = mFileHeader.indexOf(',') + 1;
            String header = "TimeStamp,";
            header += getFileHeader(mFileHeader.substring(firstDots, mFileHeader.length()),
                    mFunctionName);
            if (mEncryptionRawdata) {
                fileLogUtil.saveData(EncryptUtil.encrypt(header) + "\n");
            } else {
                fileLogUtil.saveData(header + "\n");
            }
            mFileSaveUtilMap.put(dataType, fileLogUtil);
        }

        if (datas == null || datas.length == 0) {
            return;
        }

        if (!mFileHeader.isEmpty()) {
            StringBuilder sb = new StringBuilder();
            sb.append(String.valueOf(System.currentTimeMillis())).append(",");

            // Add reference device value
            if ((datas.length >= CardiffConstants.RawdataColumn.REF_RESULT0.ordinal())
                    && mReceivedValues) {
                for (int i = 0; i < mValues.length; ++i) {
                    datas[i + CardiffConstants.RawdataColumn.REF_RESULT0.ordinal()] = mValues[i];
                }
            }

            sb.append(ArrayUtil.toString(datas));
            String line;
            if (mEncryptionRawdata) {
                line = EncryptUtil.encrypt(sb.toString());
            } else {
                line = sb.toString();
            }
            line += "\n";
            mFileSaveUtilMap.get(dataType).saveData(line);
        }
    }

    private String getFileHeader(String title, String functionName) {
        String gh31xDeviceName = "GHealth";
        for (int i = 0; i < mBleDeviceInfos.size(); i++) {
            if (mBleDeviceInfos.get(i).getType() == 1) {
                gh31xDeviceName = mBleDeviceInfos.get(i).getDeviceName();
                break;
            }
        }
        String[] cols = title.split(",");
        switch (functionName) {
            case StartArgumentsKeyEnum.AppFunction_HR:
            case StartArgumentsKeyEnum.AppFunction_ECG:
                for (int i = 0; i < mAddressList.size() && i < 16; ++i) {
                    cols[CardiffConstants.RawdataColumn.REF_RESULT0.ordinal() + i]
                            = String.format("%s_HR", mBleDeviceInfos.get(i).getDeviceName());
                }
                break;
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < cols.length; ++i) {
            sb.append(cols[i]);
            if (i != (cols.length - 1)) {
                sb.append(",");
            }
        }
        return sb.toString();
    }

    private OnHBDDataListener mOnHBDDataListener = new OnHBDDataListener() {
        @Override
        public void onDataChanged(String dataType, int[] dataArr) {
            if (dataType.equals(mFunctionName)) {
                saveData(dataType, dataArr);
            }
        }

        @Override
        public void onMeasureResult(MeasureResult result) {

            if (result.mFunctionName.compareToIgnoreCase(mFunctionName) != 0) {
                return;
            }

            int columnCnt = 1;
            int pos = mAddressList.indexOf(result.mDeviceAddress);
            if (pos < 0) {
                return;
            }

            switch (result.getFunctionName()) {
                case StartArgumentsKeyEnum.AppFunction_HR:
                case StartArgumentsKeyEnum.AppFunction_ECG:
                    columnCnt = 1;
                    if (pos >= 16) return;
                    mReceivedValues = true;
                    if (result.getTitle().equals(StartArgumentsKeyEnum.AppFunction_HR)) {
                        mValues[pos * columnCnt] = result.getIntValue();
                    }
                    break;
                default:
                    break;
            }
        }
    };

    public Map<String, FileLogUtil> getFileSaveUtilMap() {
        return mFileSaveUtilMap;
    }
}
